using System;
using System.ComponentModel;
using System.Device.Location;
using System.Globalization;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
namespace Microsoft.Phone.Controls.Maps.Core
{
	public class MapCore : MapBase
	{
		private static Size optimalViewportSize = new Size(256.0, 256.0);
		private static readonly TimeSpan isIdlePollInterval = TimeSpan.FromSeconds(0.1);
		private readonly MapInputManager inputManager;
		private readonly MapLayer modeForegroundLayer;
		private readonly MapLayer modeLayer;
		private bool arranged;
		private MapMode currentMode;
		private bool isResized = true;
		private ProjectionUpdateLevel pendingUpdate;
		private AnimationLevel preLoadRealAnimationLevel;
		private bool updatingViewPropertyFromMode;
		private bool viewChanging;
		private Size viewportSize;
		private DispatcherTimer isIdlePollTimer;
		private event EventHandler<LoadingErrorEventArgs> loadingErrorEvent
		{
			[MethodImpl(32)]
			add
			{
				this.loadingErrorEvent = (EventHandler<LoadingErrorEventArgs>)Delegate.Combine(this.loadingErrorEvent, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.loadingErrorEvent = (EventHandler<LoadingErrorEventArgs>)Delegate.Remove(this.loadingErrorEvent, value);
			}
		}
		public override event EventHandler<MapEventArgs> ViewChangeOnFrame
		{
			[MethodImpl(32)]
			add
			{
				this.ViewChangeOnFrame = (EventHandler<MapEventArgs>)Delegate.Combine(this.ViewChangeOnFrame, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.ViewChangeOnFrame = (EventHandler<MapEventArgs>)Delegate.Remove(this.ViewChangeOnFrame, value);
			}
		}
		public override event EventHandler<MapEventArgs> TargetViewChanged
		{
			[MethodImpl(32)]
			add
			{
				this.TargetViewChanged = (EventHandler<MapEventArgs>)Delegate.Combine(this.TargetViewChanged, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.TargetViewChanged = (EventHandler<MapEventArgs>)Delegate.Remove(this.TargetViewChanged, value);
			}
		}
		public override event EventHandler<MapEventArgs> ViewChangeStart
		{
			[MethodImpl(32)]
			add
			{
				this.ViewChangeStart = (EventHandler<MapEventArgs>)Delegate.Combine(this.ViewChangeStart, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.ViewChangeStart = (EventHandler<MapEventArgs>)Delegate.Remove(this.ViewChangeStart, value);
			}
		}
		public override event EventHandler<MapEventArgs> ViewChangeEnd
		{
			[MethodImpl(32)]
			add
			{
				this.ViewChangeEnd = (EventHandler<MapEventArgs>)Delegate.Combine(this.ViewChangeEnd, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.ViewChangeEnd = (EventHandler<MapEventArgs>)Delegate.Remove(this.ViewChangeEnd, value);
			}
		}
		public override event EventHandler<MapEventArgs> ModeChanged
		{
			[MethodImpl(32)]
			add
			{
				this.ModeChanged = (EventHandler<MapEventArgs>)Delegate.Combine(this.ModeChanged, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.ModeChanged = (EventHandler<MapEventArgs>)Delegate.Remove(this.ModeChanged, value);
			}
		}
		public override event EventHandler<LoadingErrorEventArgs> LoadingError
		{
			add
			{
				if (this.LoadingException != null && value != null)
				{
					value.Invoke(this, new LoadingErrorEventArgs(this.LoadingException));
				}
				this.loadingErrorEvent = (EventHandler<LoadingErrorEventArgs>)Delegate.Combine(this.loadingErrorEvent, value);
			}
			remove
			{
				this.loadingErrorEvent = (EventHandler<LoadingErrorEventArgs>)Delegate.Remove(this.loadingErrorEvent, value);
			}
		}
		public override event EventHandler<MapDragEventArgs> MapPan
		{
			add
			{
				this.inputManager.TouchDrag += value;
			}
			remove
			{
				this.inputManager.TouchDrag -= value;
			}
		}
		public override event EventHandler<MapZoomEventArgs> MapZoom
		{
			add
			{
				this.inputManager.TouchZoom += value;
			}
			remove
			{
				this.inputManager.TouchZoom -= value;
			}
		}
		public override event EventHandler MapResolved
		{
			[MethodImpl(32)]
			add
			{
				this.MapResolved = (EventHandler)Delegate.Combine(this.MapResolved, value);
			}
			[MethodImpl(32)]
			remove
			{
				this.MapResolved = (EventHandler)Delegate.Remove(this.MapResolved, value);
			}
		}
		internal MapInputManager InputManager
		{
			get
			{
				return this.inputManager;
			}
		}
		public override bool IsDownloading
		{
			get
			{
				return this.currentMode != null && this.currentMode.IsDownloading;
			}
		}
		public override bool IsIdle
		{
			get
			{
				return this.currentMode != null && (this.currentMode.IsIdle && !this.viewChanging) && this.arranged;
			}
		}
		public override Size ViewportSize
		{
			get
			{
				return this.viewportSize;
			}
		}
		public override GeoCoordinate TargetCenter
		{
			get
			{
				return this.currentMode.TargetCenter;
			}
		}
		public override double TargetZoomLevel
		{
			get
			{
				return this.currentMode.TargetZoomLevel;
			}
		}
		public override double TargetHeading
		{
			get
			{
				return this.currentMode.TargetHeading;
			}
		}
		public override double TargetPitch
		{
			get
			{
				return this.currentMode.TargetPitch;
			}
		}
		public override LocationRect BoundingRectangle
		{
			get
			{
				return this.currentMode.BoundingRectangle;
			}
		}
		public override LocationRect TargetBoundingRectangle
		{
			get
			{
				return this.currentMode.TargetBoundingRectangle;
			}
		}
		internal Point CenterPoint
		{
			get
			{
				return this.LocationToViewportPoint(base.Center);
			}
			set
			{
				base.Center = this.ViewportPointToLocation(value);
			}
		}
		protected internal Exception LoadingException
		{
			get;
			internal set;
		}
		private static long Timestamp
		{
			get
			{
				return DateTime.get_UtcNow().get_Ticks();
			}
		}
		protected MapCore()
		{
			base.RootLayer.set_Clip(new RectangleGeometry());
			this.viewportSize = MapCore.optimalViewportSize;
			this.currentMode = new NullMode();
			this.currentMode.AnimationLevel = AnimationLevel.None;
			this.preLoadRealAnimationLevel = AnimationLevel.Full;
			this.modeLayer = new MapLayer();
			this.modeForegroundLayer = new MapLayer();
			base.RootLayer.get_Children().Insert(0, this.modeLayer);
			base.RootLayer.get_Children().Add(this.modeForegroundLayer);
			this.inputManager = new MapInputManager(this);
			base.add_SizeChanged(new SizeChangedEventHandler(this.MapCore_SizeChanged));
			DispatcherTimer dispatcherTimer = new DispatcherTimer();
			dispatcherTimer.set_Interval(MapCore.isIdlePollInterval);
			this.isIdlePollTimer = dispatcherTimer;
			RoutedEventHandler routedEventHandler = delegate(object sender, RoutedEventArgs e)
			{
				if (this.isIdlePollTimer != null)
				{
					this.isIdlePollTimer.remove_Tick(new EventHandler(this.isIdlePollTimer_Tick));
				}
			};
			base.add_Unloaded(routedEventHandler);
		}
		public override void SetMode(MapMode newMode, bool transferSettings)
		{
			if (transferSettings && newMode.Content != null && VisualTreeHelper.GetParent(newMode.Content) != null)
			{
				throw new ArgumentException(ExceptionStrings.InvalidMode);
			}
			GeoCoordinate targetCenter = this.currentMode.TargetCenter;
			double targetZoomLevel = this.currentMode.TargetZoomLevel;
			double targetHeading = this.currentMode.TargetHeading;
			double targetPitch = this.currentMode.TargetPitch;
			AnimationLevel animationLevel = this.currentMode.AnimationLevel;
			newMode.Activating(this.currentMode, this.modeLayer, this.modeForegroundLayer);
			this.currentMode.TargetViewChanged -= new EventHandler<MapEventArgs>(this.currentMode_TargetViewChanged);
			this.currentMode.ProjectionChanged -= new EventHandler<ProjectionChangedEventArgs>(this.currentMode_ProjectionChanged);
			this.currentMode.Deactivating();
			this.currentMode = newMode;
			this.currentMode.ViewportSizeChanged(this.ViewportSize);
			if (transferSettings)
			{
				this.modeLayer.get_Children().Clear();
				this.modeForegroundLayer.get_Children().Clear();
				if (this.currentMode.Content != null)
				{
					this.modeLayer.get_Children().Add(this.currentMode.Content);
				}
				if (this.currentMode.ForegroundContent != null)
				{
					this.modeForegroundLayer.get_Children().Add(this.currentMode.ForegroundContent);
				}
				this.currentMode.CredentialsProvider = base.CredentialsProvider;
				this.currentMode.Culture = base.Culture;
				this.currentMode.AnimationLevel = animationLevel;
				this.currentMode.Activated(this.modeLayer, this.modeForegroundLayer);
				this.currentMode.SetView(targetCenter, targetZoomLevel, targetHeading, targetPitch, false);
				this.ProjectionUpdated(ProjectionUpdateLevel.Full);
			}
			else
			{
				this.currentMode.Activated(this.modeLayer, this.modeForegroundLayer);
			}
			this.currentMode.TargetViewChanged += new EventHandler<MapEventArgs>(this.currentMode_TargetViewChanged);
			this.currentMode.ProjectionChanged += new EventHandler<ProjectionChangedEventArgs>(this.currentMode_ProjectionChanged);
			this.UpdateViewFromMode();
			if (this.ModeChanged != null)
			{
				this.ModeChanged.Invoke(this, new MapEventArgs());
			}
		}
		public override bool TryViewportPointToLocation(Point viewportPoint, out GeoCoordinate location)
		{
			return this.currentMode.TryViewportPointToLocation(viewportPoint, out location);
		}
		public override GeoCoordinate ViewportPointToLocation(Point viewportPoint)
		{
			return this.currentMode.ViewportPointToLocation(viewportPoint);
		}
		public override bool TryLocationToViewportPoint(GeoCoordinate location, out Point viewportPoint)
		{
			return this.currentMode.TryLocationToViewportPoint(location, out viewportPoint);
		}
		public override Point LocationToViewportPoint(GeoCoordinate location)
		{
			return this.currentMode.LocationToViewportPoint(location);
		}
		public override void SetView(GeoCoordinate center, double zoomLevel)
		{
			this.SetView(center, zoomLevel, this.currentMode.TargetHeading);
		}
		public override void SetView(GeoCoordinate center, double zoomLevel, double heading)
		{
			this.SetView(center, zoomLevel, heading, this.currentMode.TargetPitch);
		}
		public override void SetView(GeoCoordinate center, double zoomLevel, double heading, double pitch)
		{
			this.currentMode.SetView(center, zoomLevel, heading, pitch, this.arranged && base.AnimationLevel == AnimationLevel.Full && !DesignerProperties.GetIsInDesignMode(this));
		}
		public override void SetView(LocationRect boundingRectangle)
		{
			this.currentMode.SetView(boundingRectangle, this.arranged && base.AnimationLevel == AnimationLevel.Full && !DesignerProperties.GetIsInDesignMode(this));
		}
		protected override void OnCenterChanged(DependencyPropertyChangedEventArgs eventArgs)
		{
			if (!this.updatingViewPropertyFromMode && eventArgs.get_NewValue() != null)
			{
				GeoCoordinate geoCoordinate = eventArgs.get_NewValue() as GeoCoordinate;
				this.currentMode.Center = geoCoordinate;
				if (this.currentMode.Center != geoCoordinate)
				{
					this.updatingViewPropertyFromMode = true;
					base.Center = this.currentMode.Center;
					this.updatingViewPropertyFromMode = false;
				}
			}
		}
		protected override void OnZoomLevelChanged(DependencyPropertyChangedEventArgs eventArgs)
		{
			if (!this.updatingViewPropertyFromMode)
			{
				double num = (double)eventArgs.get_NewValue();
				this.currentMode.ZoomLevel = num;
				if (this.currentMode.ZoomLevel != num)
				{
					this.updatingViewPropertyFromMode = true;
					base.ZoomLevel = this.currentMode.ZoomLevel;
					this.updatingViewPropertyFromMode = false;
				}
			}
		}
		protected override void OnHeadingChanged(DependencyPropertyChangedEventArgs eventArgs)
		{
			if (!this.updatingViewPropertyFromMode)
			{
				double num = (double)eventArgs.get_NewValue();
				this.currentMode.Heading = num;
				if (this.currentMode.Heading != num)
				{
					this.updatingViewPropertyFromMode = true;
					base.Heading = this.currentMode.Heading;
					this.updatingViewPropertyFromMode = false;
				}
			}
		}
		protected override void OnPitchChanged(DependencyPropertyChangedEventArgs eventArgs)
		{
			if (!this.updatingViewPropertyFromMode)
			{
				double num = (double)eventArgs.get_NewValue();
				this.currentMode.Pitch = num;
				if (this.currentMode.Pitch != num)
				{
					this.updatingViewPropertyFromMode = true;
					base.Pitch = this.currentMode.Pitch;
					this.updatingViewPropertyFromMode = false;
				}
			}
		}
		protected internal override void ProjectionUpdated(ProjectionUpdateLevel updateLevel)
		{
			this.pendingUpdate |= updateLevel;
			if (this.pendingUpdate != ProjectionUpdateLevel.None)
			{
				base.InvalidateMeasure();
			}
		}
		private void currentMode_ProjectionChanged(object sender, ProjectionChangedEventArgs e)
		{
			this.UpdateViewFromMode();
			this.pendingUpdate |= e.UpdateLevel;
			if (this.pendingUpdate != ProjectionUpdateLevel.None)
			{
				base.InvalidateMeasure();
			}
		}
		private void UpdateViewFromMode()
		{
			this.updatingViewPropertyFromMode = true;
			if (base.Center != this.currentMode.Center)
			{
				base.Center = this.currentMode.Center;
			}
			if (base.ZoomLevel != this.currentMode.ZoomLevel)
			{
				base.ZoomLevel = this.currentMode.ZoomLevel;
			}
			if (base.Heading != this.currentMode.Heading)
			{
				base.Heading = this.currentMode.Heading;
			}
			if (base.Pitch != this.currentMode.Pitch)
			{
				base.Pitch = this.currentMode.Pitch;
			}
			this.updatingViewPropertyFromMode = false;
		}
		private void Update()
		{
			if (this.pendingUpdate != ProjectionUpdateLevel.None)
			{
				if (!this.viewChanging)
				{
					this.viewChanging = true;
					if (this.ViewChangeStart != null)
					{
						this.ViewChangeStart.Invoke(this, new MapEventArgs());
					}
				}
				base.RootLayer.ProjectionUpdated(this.pendingUpdate);
				if (this.ViewChangeOnFrame != null)
				{
					this.ViewChangeOnFrame.Invoke(this, new MapEventArgs());
				}
				base.get_Dispatcher().BeginInvoke(delegate
				{
					base.InvalidateMeasure();
				});
			}
			else
			{
				if (this.viewChanging && this.pendingUpdate == ProjectionUpdateLevel.None)
				{
					this.viewChanging = false;
					if (this.ViewChangeEnd != null)
					{
						this.ViewChangeEnd.Invoke(this, new MapEventArgs());
					}
					this.isIdlePollTimer.add_Tick(new EventHandler(this.isIdlePollTimer_Tick));
					this.isIdlePollTimer.Start();
				}
			}
			this.pendingUpdate = ProjectionUpdateLevel.None;
		}
		private void isIdlePollTimer_Tick(object sender, EventArgs e)
		{
			if (this.IsIdle)
			{
				this.isIdlePollTimer.Stop();
				this.isIdlePollTimer.remove_Tick(new EventHandler(this.isIdlePollTimer_Tick));
				EventHandler mapResolved = this.MapResolved;
				if (mapResolved != null)
				{
					mapResolved.Invoke(this, EventArgs.Empty);
				}
			}
		}
		private void MapCore_SizeChanged(object sender, SizeChangedEventArgs e)
		{
			((RectangleGeometry)base.RootLayer.get_Clip()).set_Rect(new Rect(0.0, 0.0, e.get_NewSize().get_Width(), e.get_NewSize().get_Height()));
			this.isResized = true;
		}
		private void UpdateViewportSize(Size pendingSize)
		{
			if (pendingSize != this.viewportSize)
			{
				Size size = this.viewportSize;
				this.viewportSize = new Size((double.IsInfinity(pendingSize.get_Width()) | double.IsNaN(pendingSize.get_Width())) ? MapCore.optimalViewportSize.get_Width() : pendingSize.get_Width(), (double.IsInfinity(pendingSize.get_Height()) | double.IsNaN(pendingSize.get_Height())) ? MapCore.optimalViewportSize.get_Height() : pendingSize.get_Height());
				if (size != this.viewportSize)
				{
					this.currentMode.ViewportSizeChanged(this.viewportSize);
				}
			}
		}
		protected override Size MeasureOverride(Size availableSize)
		{
			if (this.isResized)
			{
				this.UpdateViewportSize(availableSize);
				this.isResized = false;
			}
			this.Update();
			((UIElement)base.get_Content()).Measure(this.ViewportSize);
			return new Size(Math.Min(MapCore.optimalViewportSize.get_Width(), availableSize.get_Width()), Math.Min(MapCore.optimalViewportSize.get_Height(), availableSize.get_Height()));
		}
		protected override Size ArrangeOverride(Size finalSize)
		{
			this.UpdateViewportSize(finalSize);
			((UIElement)base.get_Content()).Arrange(new Rect(0.0, 0.0, this.ViewportSize.get_Width(), this.ViewportSize.get_Height()));
			if (!this.arranged)
			{
				this.arranged = true;
				this.OnFirstFrame();
			}
			return this.ViewportSize;
		}
		protected virtual void OnFirstFrame()
		{
			base.AnimationLevel = this.preLoadRealAnimationLevel;
		}
		protected override void OnCultureChanged(DependencyPropertyChangedEventArgs eventArgs)
		{
			base.OnCultureChanged(eventArgs);
			CultureInfo cultureInfo = eventArgs.get_NewValue() as CultureInfo;
			if (cultureInfo != null)
			{
				this.currentMode.Culture = cultureInfo;
			}
		}
		protected override void OnCredentialsProviderChanged(DependencyPropertyChangedEventArgs eventArgs)
		{
			if (eventArgs.get_OldValue() == this.currentMode.CredentialsProvider)
			{
				this.currentMode.CredentialsProvider = (eventArgs.get_NewValue() as CredentialsProvider);
			}
		}
		protected override void OnAnimationLevelChanged(DependencyPropertyChangedEventArgs eventArgs)
		{
			AnimationLevel animationLevel = (AnimationLevel)eventArgs.get_NewValue();
			if (this.arranged && !DesignerProperties.GetIsInDesignMode(this))
			{
				this.currentMode.AnimationLevel = animationLevel;
				return;
			}
			this.preLoadRealAnimationLevel = animationLevel;
		}
		protected override void OnModeChanged(DependencyPropertyChangedEventArgs eventArgs)
		{
			MapMode newMode = eventArgs.get_NewValue() as MapMode;
			this.SetMode(newMode, true);
		}
		internal void ThrowLoadingException(Exception e)
		{
			if (this.LoadingException == null && e != null)
			{
				this.LoadingException = e;
				EventHandler<LoadingErrorEventArgs> eventHandler = this.loadingErrorEvent;
				if (eventHandler != null)
				{
					eventHandler.Invoke(this, new LoadingErrorEventArgs(this.LoadingException));
				}
			}
		}
		private void currentMode_TargetViewChanged(object sender, MapEventArgs e)
		{
			EventHandler<MapEventArgs> targetViewChanged = this.TargetViewChanged;
			if (targetViewChanged != null)
			{
				targetViewChanged.Invoke(this, e);
			}
		}
	}
}
